import * as Mongoose from 'mongoose';
import * as Grid from 'gridfs-stream'
import * as fs from 'fs';
import * as Koa from 'koa';
import * as request from 'request';
import { readFileSync, readFile } from 'fs';
import * as path from 'path';
import { Exceptions, Tools } from "./../kalend";
import config from './config';
import http = require('http');
var mammoth = require("mammoth");

class FilesBasicGridfs {
    private gfs: Grid.Grid;

    public makesureGrid() {
        if (!this.gfs) { this.gfs = Grid(Mongoose.connection.db, Mongoose.mongo); }
    }
    async baseimgwrite(base64Data: any, name: any) {
        var imageBuffer = await this.decodeBase64Image(base64Data);
        //验证图片类型；
        const userUploadedImagePath = path.join(process.cwd(), "example.png");
        require('fs').writeFile(userUploadedImagePath, imageBuffer.data,
            function () {
                console.log('DEBUG - feed:message: Saved to disk image attached by user:', userUploadedImagePath);
            });
        let result1 = await fsfiles.upload({ path: userUploadedImagePath, name: name });
        fs.unlinkSync(userUploadedImagePath);
        return result1;
    }

    /**
     * 多个文件上传
     * @param file 文件流
     */
    async uploads(files: any) {
        let result: Array<any> = [];
        for (let file of files) {
            const paths = file.path;
            const fileInfo: any = await new Promise((resolve, reject) => {
                try {
                    let writestream = this.gfs.createWriteStream({
                        filename: file.name
                    });

                    fs.createReadStream(paths, { autoClose: true })
                        .pipe(writestream)
                        .on('close', () => { });
                    writestream.on('close', (file: any) => {
                        resolve(file);
                    });
                    writestream.on('error', (err: any) => {
                        reject(err);
                    });
                    //pdf文件存入服务器对应文件夹目录
                    var filetypes = config.get("file")["filetypes"];
                    let validataname = Tools.filenamevalidation(file.name, filetypes);
                    if (validataname) {
                        const readStream = fs.createReadStream(paths);
                        const writeStream = fs.createWriteStream(config.get("file")["pdfpath"] + file.name)
                        readStream.pipe(writeStream)
                        readStream.on('error', (error) => {
                            console.log('readStream error', error.message);
                        })
                        writeStream.on('error', (error) => {
                            console.log('writeStream error', error.message);
                        })
                    }
                } catch (err) {
                    reject(err);
                }
            });
            result.push(fileInfo);
        }
        return result;
    }
    /**
     * 单个文件上传
     * @param file 文件流
     */
    async upload(file: any) {
        const path = file.path;
        const fileInfo: any = await new Promise((resolve, reject) => {
            try {
                let writestream = this.gfs.createWriteStream({
                    filename: file.name
                });

                fs.createReadStream(path, { autoClose: true })
                    .pipe(writestream)
                    .on('close', () => { });

                writestream.on('close', (file: any) => {
                    resolve(file);
                });
                writestream.on('error', (err: any) => {
                    reject(err);
                });
            } catch (err) {
                reject(err);
            }
        });
        //console.log('上传文件结果：'+fileInfo)
        var apiurl = config.get("apiforarea")["imgurl"]
        return apiurl + fileInfo._id;
    }

    /**
     * 文件下载
     * @param res 
     * @param id 
     */
    async download(ctx: Koa.Context, id: any): Promise<any> {
        try {
            const filter = { _id: id };
            const item: any = await new Promise((resolve, reject) => {
                this.gfs.findOne(filter, (err, item) => {
                    if (err) {
                        reject(err);
                    } else {
                        if (item) {
                            var readstream = this.gfs.createReadStream(item);
                            ctx.body = readstream;
                            resolve(item);
                        } else {
                            reject(Exceptions.noFound());
                        }
                    }
                });
            });
            ctx.response.set("Content-Disposition", `attachment;filename=${encodeURI(item.filename)}`);
            ctx.response.set("Content-Type", `${item.contentType}`);

        }
        catch (e) {
            console.log(e);
        }
    }


    /**
 * 文件下载
 * @param res 
 * @param id 
 */
    async downloaddocandpdf(ctx: Koa.Context, id: any): Promise<any> {
        try {
            const filter = { _id: id };
            const item: any = await new Promise((resolve, reject) => {
                this.gfs.findOne(filter, (err, item) => {
                    if (err) {
                        reject(err);
                    } else {
                        if (item) {
                            var readstream = this.gfs.createReadStream(item);
                            ctx.body = readstream;
                            resolve(item);
                        } else {
                            reject(Exceptions.noFound());
                        }
                    }
                });
            });
            ctx.response.set("Content-Disposition", `attachment;filename=${encodeURI(item.filename)}`);

            const pdfrgx = /\.pdf$/;
            const docrgx = /\.doc$/;

            if (pdfrgx.test(item.filename)) {
                ctx.response.set("Content-Type", "application/pdf");
            }
            else if (docrgx.test(item.filename)) {
                ctx.response.set("Content-Type", "application/msword");
            } else {
                ctx.response.set("Content-Type", `${item.contentType}`);
            }


        }
        catch (e) {
            console.log(e);
        }
    }

    async downloadById(res: Koa.Response, id: any): Promise<any> {
        var buffer: any;
        var responseData: any[] = [];
        const filter = { _id: id };
        let filename: any;
        let contentType: any;
        await new Promise((resolve, reject) => {
            this.gfs.findOne(filter, async (err, item) => {
                if (err) {
                    reject(err);
                } else {
                    if (item) {
                        const lastindex = (item.filename as string).lastIndexOf('.');
                        const fileExt = item.filename.substr(lastindex, item.filename.length - lastindex);
                        var fs_write = fs.createWriteStream("files/" + 'aa' + fileExt);
                        var readstream = this.gfs.createReadStream(filter);
                        readstream.pipe(fs_write);
                        fs_write.on("close", function () {
                        });
                        readstream.on("data", function (chunk: any) {
                            responseData.push(chunk)
                        });
                        readstream.on("end", function () {
                            buffer = Buffer.concat(responseData);
                            contentType = item.contentType;
                            resolve(item);
                        });
                        filename = item.filename;
                    } else {
                        resolve({});
                    }
                }
            });
        });
        const data = {
            body: buffer,
            filename: filename,
            contentType: contentType
        };
        return data;
    }

    async downloadFile(ctx: Koa.Context, path: any) {
        ctx.body = readFileSync(path);
        ctx.response.set("Content-Disposition", `attachment;filename=''}`);
        ctx.response.set("Content-Type", ``);
    }


    /**
    * 图片上传
    * @param file {name:name2,path:uri}
    */
    async  Imageupload(file: any, ctx: Koa.Context): Promise<http.IncomingMessage> {
        let datatime = new Date().getTime();
        const path = file.path;
        var that = this;
        var promise = new Promise<http.IncomingMessage>(async resolve => {

            let writestream = that.gfs.createWriteStream({
                filename: datatime + '.jpg'
            });
            request(path).pipe(writestream);
            writestream.on('close', (file: any) => {
                resolve(file);
            });

        });
        return promise;
    }
    /*图片数据获取
  *@param 
  */
    async getimg(res: Koa.Response, id: any): Promise<any> {
        var buffer: any;
        var responseData: any[] = [];
        const filter = { _id: id };
        let filename: any;
        let contentType: any;
        await new Promise((resolve, reject) => {
            this.gfs.findOne(filter, async (err, item) => {
                if (err) {
                    reject(err);
                } else {
                    if (item) {
                        //var fs_write = fs.createWriteStream("files/" + "bb.png");
                        var readstream = this.gfs.createReadStream(filter);
                        //readstream.pipe(fs_write);
                        // fs_write.on("close", function () {
                        // });
                        // a = readFileSync("files/bb.png");
                        readstream.on("data", function (chunk: any) {
                            responseData.push(chunk)
                        });
                        readstream.on("end", function () {
                            buffer = Buffer.concat(responseData);
                            contentType = item.contentType;
                            resolve(item);
                        });
                        filename = item.filename;
                    } else {
                        const info = (await this.defImage())
                        buffer = info.body;
                        filename = 'default.png';
                        contentType = info.contentType;
                        resolve({});
                    }
                }
            });
        });
        const data = {
            body: buffer,
            filename: filename,
            contentType: contentType
        };
        return data;
    }


    //获取word文档内容
    async getFile(file: any) {
        var resData = await new Promise<http.IncomingMessage>(async resolve => {
            //解析word文档内容
            mammoth.convertToHtml({ path: file })
                .then(function (result: any) {
                    resolve(result);
                });
        });
        return resData;
    };


    //根据ID获取Buffer
    async getBufferById(id: any) {
        const filter = { _id: id };
        const fileInfo: any = await new Promise((resolve, reject) => {
            var readstream = this.gfs.createReadStream(filter);
            readstream.on("data", function (chunk: any) {
                resolve(chunk);
            })
        });
        return fileInfo;
    };

    //获取pdf和doc文件id和文件名
    async getidandnamebytype(regx: any) {
        let wrex = regx == "default" ? ".pdf|.doc" : regx;
        var res = await this.gfs.files.aggregate([{ $match: { filename: { $regex: ".pdf|.doc" } } }, { $match: { filename: { $regex: wrex } } }, { $project: { _id: 1, filename: 1, uploadDate: 1 } }]).toArray();

        return res;
    };

    async getBufferByIds(id: any) {
        const filter = { _id: id };
        var responseData: any[] = [];
        const fileInfo: any = await new Promise((resolve, reject) => {
            var readstream = this.gfs.createReadStream(filter);
            readstream.on("data", function (chunk: any) {
                // resolve(chunk);
                responseData.push(chunk)
            });
            readstream.on("end", function () {
                let buffer = Buffer.concat(responseData);
                // contentType = item.contentType;
                resolve(buffer);
            });
        });
        return fileInfo;
    };
    /*传入id，路径，和文件名*/
    async saveBufferToFile(id: any, toPath: any, fileName: any) {
        const buffer = await this.getBufferByIds(id);
        fs.writeFile(toPath + `/${fileName}`, buffer, { flag: 'w', encoding: 'utf-8', mode: '0666' }, function (err) {
            if (err) {
                console.log("文件写入失败");
            } else {
                console.log("文件写入成功");
            }
        });

    }
    /** 读取文件内容 */
    async readStaticFile(ctx: Koa.Context, filename: any) {
        var fs = require('fs');
        let filepath = `${config.filePath.staticfile}/${filename}`
        var result = JSON.parse(fs.readFileSync(filepath));
        return result;
    }


    async uploadBase64Image(base64Data: any) {
        var imageBuffer = await this.decodeBase64Image(base64Data);
        const userUploadedImagePath = path.join(process.cwd(), "example.png");// 'file/example.png' ;
        require('fs').writeFile(userUploadedImagePath, imageBuffer.data,
            function () {
                console.log('DEBUG - feed:message: Saved to disk image attached by user:', userUploadedImagePath);
            });
        let result1 = await fsfiles.upload({ path: userUploadedImagePath, name: imageBuffer.name });
        fs.unlinkSync(userUploadedImagePath);
        return result1;
    }
    async decodeBase64Image(dataString: any) {
        const matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
        const response: any = {};

        if (matches.length !== 3) {
            return new Error('Invalid input string');
        }
        response.type = matches[1];
        response.data = new Buffer(matches[2], 'base64');


        var crypto = require('crypto');
        var seed = crypto.randomBytes(20);
        var uniqueSHA1String = crypto
            .createHash('sha1')
            .update(seed)
            .digest('hex');
        const imageTypeDetected = matches[1].match(/\/(.*?)$/);


        response.name = `${uniqueSHA1String}.${imageTypeDetected[1]}`;
        return response;
    }
    /*默认图片*/
    private async defImage(encoding: BufferEncoding = 'binary') {
        const result: { body?: Buffer, contentType?: string } = {};
        return new Promise<any>((resolve) => {

            readFile(`${config.filePath.images}/default.png`, encoding, (err, data) => {
                if (err) {
                    // TODO: 默认照片的 binary
                    resolve({
                        body: new Buffer('', encoding),
                        contentType: 'image/png'
                    });
                } else {
                    resolve({
                        body: new Buffer(data, encoding),
                        contentType: 'image/png'
                    });
                }
            });
        });
    }
}

export const fsfiles = new FilesBasicGridfs();